/* who2.c - 读取 /etc/utmp 并列出其中的信息  
 *         - 抑制空记录  
 *         - 格式化时间  
 */  
#include <stdio.h>  
#include <unistd.h>  
#include <utmp.h>  
#include <fcntl.h>  
#include <time.h>  

/* #define SHOWHOST */  

void showtime(long);  
void show_info(struct utmp *);  

int main()  
{  
    struct utmp utbuf;       /* 将信息读入此处 */  
    int utmpfd;              /* 从此描述符读取 */  

    /* 打开 utmp 文件进行只读操作 */  
    if ((utmpfd = open(UTMP_FILE, O_RDONLY)) == -1) {  
        perror(UTMP_FILE);  
        return 1; // 改为返回错误码  
    }  

    /* 读取 utmp 文件中的记录 */  
    while (read(utmpfd, &utbuf, sizeof(utbuf)) == sizeof(utbuf)) {  
        show_info(&utbuf);  
    }  

    close(utmpfd);  
    return 0;  
}  

/*  
 * show_info()  
 * 显示 utmp 结构体的内容  
 * 以人类可读的形式输出  
 * 如果记录没有用户名，则不显示任何内容  
 */  
void show_info(struct utmp *utbufp)  
{  
    // 仅处理用户进程类型的记录  
    if (utbufp->ut_type != USER_PROCESS) {  
        return;  
    }  

    printf("%-8.8s", utbufp->ut_name); /* 登录名 */  
    printf(" ");                        /* 空格 */  
    printf("%-8.8s", utbufp->ut_line); /* 终端 */  
    printf(" ");                        /* 空格 */  
    showtime(utbufp->ut_time);         /* 显示时间 */  
#ifdef SHOWHOST  
    if (utbufp->ut_host[0] != '\0') {  
        printf(" (%s)", utbufp->ut_host); /* 机器名 */  
    }  
#endif  
    printf("\n");                      /* 换行 */  
}  

/*  
 * showtime()  
 * 以人类可读的格式显示时间  
 * 使用 ctime 构建字符串，然后提取其中的部分  
 * 注意：%12.12s 打印宽度为 12 个字符的字符串，并限制为 12 字符。  
 */  
void showtime(long timeval)  
{  
    char *cp;                       /* 用于存储时间字符串的地址 */  

    cp = ctime(&timeval);           /* 将时间转换为字符串 */  
    /* 字符串格式：Mon Feb  4 00:46:40 EST 1991 */  
    printf("%12.12s", cp + 4);      /* 从位置 4 开始选择 12 个字符 */  
}
